基础

在 Vue 中子组件为何不可以修改父组件传递的 Prop,如果修改了,Vue 是如何监控到属性的修改并给出警告的

子组件为何不可以修改父组件传递的 Prop 单向数据流,易于监测数据的流动,出现了错误可以更加迅速的定位到错误发生的位置。 如果修改了,Vue 是如何监控到属性的修改并给出警告的。

if (process.env.NODE_ENV !== "production") {
  var hyphenatedKey = hyphenate(key);
  if (
    isReservedAttribute(hyphenatedKey) ||
    config.isReservedAttr(hyphenatedKey)
  ) {
    warn(
      '"' +
        hyphenatedKey +
        '" is a reserved attribute and cannot be used as component prop.',
      vm
    );
  }
  defineReactive$$1(props, key, value, function () {
    if (!isRoot && !isUpdatingChildComponent) {
      warn(
        "Avoid mutating a prop directly since the value will be " +
          "overwritten whenever the parent component re-renders. " +
          "Instead, use a data or computed property based on the prop's " +
          'value. Prop being mutated: "' +
          key +
          '"',
        vm
      );
    }
  });
}

在 initProps 的时候,在 defineReactive 时通过判断是否在开发环境,如果是开发环境,会在触发 set 的时候判断是否此 key 是否处于 updatingChildren 中被修改,如果不是,说明此修改来自子组件,触发 warning 提示。

需要特别注意的是,当你从子组件修改的 prop 属于基础类型时会触发提示。 这种情况下,你是无法修改父组件的数据源的, 因为基础类型赋值时是值拷贝。你直接将另一个非基础类型(Object, array)赋值到此 key 时也会触发提示(但实际上不会影响父组件的数据源), 当你修改 object 的属性时不会触发提示,并且会修改父组件数据源的数据。

组件通信

组件通信一般分为以下几种情况:

  • 父子组件通信
  • 兄弟组件通信
  • 跨多层级组件通信
  • 任意组件

兄弟组件通信

通过 this.$parent.$children,在 $children 中可以通过组件 name 查询到需要的组件实例,然后进行通信。

父子组件通信

  1. emit/props
  2. $parent.xxx
  3. provide/injected 跨多层次组件通信
  4. event bus
  5. Vuex
  6. $listeners.sync

任意组件

  1. event bus
  2. Vuex

Vue JSX

JSX 中指令是否还可用?

大多数指令并不能在 JSX 中使用,对于原生指令,只有 v-show 是支持的。但是大部分指令在 JSX 中可以使用表达式来替代,如:条件运算符(?:)替代 v-if、array.map 替代 v-for

对于自定义的指令,可以使用如下方式使用:

const directives = [{ name: "my-dir", value: 123, modifiers: { abc: true } }];

return <div {...{ directives }} />;

使用 jsx 的优劣

好处:

  1. 更加灵活的表达
  2. 自定义的渲染函数,ant d 中的 table , customRender 之类的渲染函数,能够更加自由的填充开发者想填写的内容
  3. html 模板与数据处于一个地方,单文件组件 template 的需要上下移动
  4. 与 TS 结合比较好, template 模板部分 vue 2.0 暂时不能很好支持
  5. 不是很确定:通常情况下, spa 不会去线上编译模板代码,所以只是开发阶段的编译速度会增加,因为 template 会被编译成 render 函数,tsx/jsx 讲道理好像没有这个过程,html 标签会直接通过 h 函数被编译成 vnode
  6. 对于需要做两个技术栈的开发者来说 是好事。

坏处:

  1. render 函数的写法需要有一定的基础
  2. 与 TS 结合之后,mixins 的写法有一定的误解性, 因为需要类型推导,所以 只能通过 Vue.extend 来实现一个 mixins ,每一个 mixins 需要写成一个 vue 类,而不是 options 的一部分,一个简单的对象即可

其他东西都没有变化,只是 template 变成了 jsx 的形式。template 本来就会被转化成一个 render 函数,现在构建时减少了一次编译。

优点:

  1. 更加灵活。
  2. 编译更快。
  3. 对于 vue2 来说是有更好的类型支持,毕竟 template 中类型支持不是很好。

缺点:

  1. 与 vue 最推崇的方式有差别,有些人不喜欢 jsx 的写法,不习惯的人写起来会比较难受。
  2. template 模式 vue 会在编译时做很多静态优化,现在 render 函数直接是用户提供,缺少了原生的这些优化。
  3. 无法使用指令
Last Updated:
Contributors: yiliang114